#pragma once
#include <boost/typeof/typeof.hpp>
#include <boost/property_tree/ptree.hpp>
#include "TextureObjManage.h"
#include "MeshObj.h"
#include "EffectObj.h"
#include "FrameManage.h"

using namespace boost::property_tree;
class NodeData
{
public:
	NodeData(DirectX::XMFLOAT4X4 mat, list<string> vLightBase = list<string>())
	{
		m_matTranform = mat;
		m_vLightBase = vLightBase;
		m_matWorld = MathHelper::Identity4x4();
	}
	
	NodeData(DirectX::XMFLOAT4X4 mat, string sLightBase)
	{
		m_matTranform = mat;
		m_matWorld = MathHelper::Identity4x4();
		m_vLightBase.push_back(sLightBase);
	}
	
	NodeData() {};
	friend ostream &operator<<(ostream &output,
		const NodeData &D)
	{
		for (int i = 0; i < 4; ++i)
		{
			for (int j = 0; j < 4; ++j)
			{
				output << D.m_matTranform.m[i][j] <<endl;

			}
		}

		

		for (int i = 0; i < 4; ++i)
		{
			for (int j = 0; j < 4; ++j)
			{
				output << (float)D.m_matWorld.m[i][j]<<endl;
			}
		}
		int iSize = D.m_vLightBase.size();
		output << iSize<<endl;
		for (string inx : D.m_vLightBase)
		{
			output << inx <<endl;
		}
		iSize = D.m_vLightCurrent.size();
		output << iSize << endl;
		for (string inx : D.m_vLightCurrent)
		{
			output << inx << endl;
		}
		return output;
	}

	friend istream &operator >> (istream  &input, NodeData &D)
	{
		for (int i = 0; i < 4; ++i)
		{
			for (int j = 0; j < 4; ++j)
			{
				input >> (float)D.m_matTranform.m[i][j];

			}
		}
		for (int i = 0; i < 4; ++i)
		{
			for (int j = 0; j < 4; ++j)
			{
				input >> (float)D.m_matWorld.m[i][j];

			}
		}

		
		int iSize;
		input >> iSize;
		for (int i=0; i<iSize; ++i)
		{
			string inx;
			input >> inx;
			D.m_vLightBase.push_back(inx);
		}

		input >> iSize;
		for (int i = 0; i < iSize; ++i)
		{
			string inx;
			input >> inx;
			D.m_vLightCurrent.push_back(inx);
		}
		return input;
	}

	DirectX::XMFLOAT4X4 GetMatWorld() const {
		return m_matWorld;
	}

	const list<string>& GetLight() const
	{
		return m_vLightCurrent;
	}

	void Update(const DirectX::XMFLOAT4X4& matParent)
	{
		XMMATRIX mat1 = XMLoadFloat4x4(&m_matTranform);
		XMMATRIX mat2 = XMLoadFloat4x4(&matParent);
		XMMATRIX mat = XMMatrixMultiply(mat1, mat2);
		XMStoreFloat4x4(&m_matWorld, mat);
		shared_ptr<LightManage> pLightManage = LightManage::GetLightCurrent();
		shared_ptr<LightManage> pLightManageBase = LightManage::GetLightBase();
		for (string s : m_vLightCurrent)
		{
			pLightManage->Remove(s);
		}
		for (string s : m_vLightBase)
		{
			LightObj l = pLightManageBase->Get(s);
			l.MutiyMat(mat);
			l.SetName(CreateUUid());
			m_vLightCurrent.push_back(l.GetName());
			pLightManage->Add(l.GetName(), l);
		}
	}
protected:
	DirectX::XMFLOAT4X4 m_matTranform, m_matWorld;;
	list<string> m_vLightBase, m_vLightCurrent;

};

class LeafData
{
public:
	LeafData(const vector<string>& mesh, string nameMaterial, string nameShader, list<string> vLightBase = list<string>())
	{
		m_vMeshObj = mesh;
		m_vLightBase = vLightBase;
		m_nameMaterial = nameMaterial;
		m_nameShader = nameShader;
	}

	LeafData() {};

	LeafData(const string& mesh, string nameMaterial, string nameShader, list<string> vLightBase = list<string>())
	{
		m_vMeshObj.push_back(mesh);
		m_vLightBase = vLightBase;
		m_nameMaterial = nameMaterial;
		m_nameShader = nameShader;
	}

	friend ostream &operator<<(ostream &output,
		const LeafData &D)
	{
		for (int i = 0; i < 4; ++i)
		{
			for (int j = 0; j < 4; ++j)
			{
				output << D.m_matWorld.m[i][j] << endl;
			}
		}

		output << D.m_vMeshObj.size() << endl;
		for (auto inx : D.m_vMeshObj)
		{
			output << inx << endl;
		}
		
		output << D.m_vLightBase.size() << endl;
		for (auto inx : D.m_vLightBase)
		{
			output << inx << endl;
		}

		output << D.m_vLightCurrent.size() << endl;
		for (auto inx : D.m_vLightCurrent)
		{
			output << inx << endl;
		}

		output << D.m_nameMaterial << endl << D.m_nameShader << endl;
		return output;
	}

	friend istream &operator >> (istream  &input, LeafData &D)
	{
		for (int i = 0; i < 4; ++i)
		{
			for (int j = 0; j < 4; ++j)
			{
				input >> D.m_matWorld.m[i][j];

			}
		}

		int iSize;
		input >> iSize;
		for (int i = 0; i < iSize; ++i)
		{
			string s;
			input >> s;
			D.m_vMeshObj.push_back(s);
		}

		input >> iSize;
		for (int i = 0; i < iSize; ++i)
		{
			string inx;
			input >> inx;
			D.m_vLightBase.push_back(inx);
		}


		input >> iSize;
		for (int i = 0; i < iSize; ++i)
		{
			string inx;
			input >> inx;
			D.m_vLightCurrent.push_back(inx);
		}

		input >> D.m_nameMaterial >> D.m_nameShader;
		return input;
	}

	list<string> GetLight()
	{
		return m_vLightCurrent;
	}

	void Update(const DirectX::XMFLOAT4X4& matParent)
	{
		m_matWorld = matParent;
		XMMATRIX mat = XMLoadFloat4x4(&matParent);
		shared_ptr<LightManage> pLightManage = LightManage::GetLightCurrent();
		shared_ptr<LightManage> pLightManageBase = LightManage::GetLightBase();
		for (string s : m_vLightCurrent)
		{
			pLightManage->Remove(s);
		}
		for (string s : m_vLightBase)
		{
			LightObj l = pLightManageBase->Get(s);
			l.MutiyMat(mat);
			l.SetName(CreateUUid());
			m_vLightCurrent.push_back(l.GetName());
			pLightManage->Add(l.GetName(), l);
		}
	}

	vector<string> GetMesh() { return m_vMeshObj; }
	string GetMaterial() { return m_nameMaterial; }
	string GetShader() { return m_nameShader; }

	DirectX::XMFLOAT4X4 GetMatWorld() const {
		return m_matWorld;
	}

public:
	DirectX::XMFLOAT4X4  m_matWorld = MathHelper::Identity4x4();;
	list<string> m_vLightBase, m_vLightCurrent;
	vector<string> m_vMeshObj;
	string m_nameMaterial;
	string m_nameShader;
};

class SceneManage :public InstanceObj<SceneManage>
{
	enum emNodeType
	{
		TYPE_NONE = 0,
		TYPE_NODE,
		TYPE_LEAF
	};
	enum emTypeKey
	{
		TYPE_NODE_NAME=0,
		TYPE_NODE_TYPE,
		TYPE_NODE_DATA,
		TYPE_NODE_ISNEED_UPDATE,
		TYPE_NODE_MAX
	};
public:
	SceneManage();

	~SceneManage();

	void InitScene();

	void CompileScene(PD3D12Device device, DXGI_FORMAT backBufferFormat, DXGI_FORMAT depthStencilFormat, bool msaaState, UINT msaaQuality);

	void UpdateScene(PD3D12Device device, PCommandList pCommandList, string sCamName = "MainCam")
	{
		vector<ScenRenderItem> vItem = GetRenderItem(device, pCommandList, sCamName);
		ScenRenderItemManage::GetInstance()->SetData(vItem);
	}
protected:
	vector<ScenRenderItem> GetRenderItem(PD3D12Device devicer, PCommandList pCommandList, string sCamName = "MainCam");

	void UpdateNode();

	emNodeType GetType(ptree tree);

	string GetName(ptree tree);

	int AddNode(ptree& treeParent, NodeData d, string sName = "");

	int AddLeaf(ptree& treeParent, LeafData d, string sName = "");

	ptree InitNodeTree(NodeData d, string sName = "");

	ptree InitLeafTree(LeafData d, string sName = "");

	emTypeKey GetKeyType(string strKey)
	{
		emTypeKey type = TYPE_NODE_MAX;
		for (int i =0; i<type;++i)
		{
			if (m_strkeyWord[i] == strKey)
			{
				type = (emTypeKey)i;
				break;
			}
		}
		return type;
	}
private:
	ptree m_treeRoot;
	const vector<string> m_strkeyWord = {"Name", "NodeType", "Data", "IsNeedUpdate"};
};

